﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace System.Windows.Controls
{
    /// <summary>
    /// Implements a base class for controls which require Button-like functionality
    /// </summary>
    [TemplateVisualState(Name="Normal", GroupName="CommonStates")]
    [TemplateVisualState(Name="MouseOver", GroupName="CommonStates")]
    [TemplateVisualState(Name="Pressed", GroupName="CommonStates")]
    [TemplateVisualState(Name="Disabled", GroupName="CommonStates")]
    [TemplateVisualState(Name="Focused", GroupName="FocusStates")]
    [TemplateVisualState(Name="Unfocused", GroupName="FocusStates")]
    public abstract class ButtonBase : System.Windows.Controls.ContentControlBase
    {
        /// <summary>
        /// Instantiates a <see cref="ButtonBase"/> instance.
        /// </summary>
        public ButtonBase()
        {
        }

        /// <summary>
        /// An event which fires when the <see cref="ButtonBase"/> has been clicked with the left mouse button.
        /// </summary>
        public event EventHandler   Click = null;

        /// <summary>
        /// The current <see cref="System.Windows.MouseState"/> of the <see cref="ButtonBase"/>.
        /// </summary>
        protected MouseState      mouseState = MouseState.Normal;

        /// <summary>
        /// Gets the current <see cref="MouseState"/> for the ButtonBase instance.
        /// </summary>
        public MouseState MouseState
        {
            get { return mouseState; }
            protected set { mouseState = value; }
        }

        /// <summary>
        /// (Override) Handles the Mouse Enter event for the <see cref="ButtonBase"/>.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Input.MouseEventArgs"/> for the event</param>
        protected override void OnMouseEnter(MouseEventArgs e)
        {
            base.OnMouseEnter(e);
            if (this.IsEnabled)
            {
                mouseState = MouseState.MouseOver;
                GoToState(true, "MouseOver");
            }
        }

        /// <summary>
        /// (Override) Handles the Mouse Leave event for the <see cref="ButtonBase"/>.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Input.MouseEventArgs"/> for the event</param>
        protected override void OnMouseLeave(MouseEventArgs e)
        {
            base.OnMouseLeave(e);
            if (this.IsEnabled)
            {
                mouseState = MouseState.Normal;
                GoToState(true, "Normal");
            }
        }

        /// <summary>
        /// (Override) Handles the Mouse Left Button Down event for the <see cref="ButtonBase"/>.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> for the event</param>
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonDown(e);
            if (this.IsEnabled)
            {
                mouseState = MouseState.Pressed;
                GoToState(true, "Pressed");
                this.CaptureMouse();
            }

            if (!this.IsFocused) this.Focus();
        }

        /// <summary>
        /// (Override) Handles the Mouse Left Button Up event for the <see cref="ButtonBase"/>.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> for the event</param>
        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonUp(e);
            if (this.IsEnabled)
            {
                this.ReleaseMouseCapture();

                Point pt = e.GetPosition(this);
                if (pt.X >= 0 && pt.X <= this.Width && pt.Y >= 0 && pt.Y <= this.Height)
                {
                    mouseState = MouseState.MouseOver;
                    GoToState(true, "MouseOver");
                }
                else
                {
                    mouseState = MouseState.Normal;
                    GoToState(true, "Normal");
                }

                OnClick();
            }
        }

        /// <summary>
        /// (Override) Handles the dispatching of the Click event for the <see cref="ButtonBase"/>.
        /// </summary>
        protected virtual void OnClick()
        {
            if (this.Click != null) this.Click(this, EventArgs.Empty);
        }

        /// <summary>
        /// (Override) Changes focus state for the <see cref="ButtonBase"/> when focus is gained.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> for the event</param>
        protected override void OnGotFocus(RoutedEventArgs e)
        {
            base.OnGotFocus(e);
            if (this.IsEnabled) GoToState(true, "Focused");
        }

        /// <summary>
        /// (Override) Changes focus state for the <see cref="ButtonBase"/> when focus is lost.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> for the event</param>
        protected override void OnLostFocus(RoutedEventArgs e)
        {
            base.OnLostFocus(e);
            if (this.IsEnabled) GoToState(true, "Unfocused");
        }

        /// <summary>
        /// (Override) Changes state for the <see cref="ButtonBase"/> when enabled or disabled.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> for the event</param>
        protected override void OnIsEnabledChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnIsEnabledChanged(e);
            GoToState(true, (this.IsEnabled ? "Normal" : "Disabled"));            
        }

        /// <summary>
        /// (Override) Handles Key Down events for the <see cref="ButtonBase"/> instance.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Input.KeyEventArgs"/> for the event</param>
        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);
            if (this.IsEnabled && e.Key == Key.Space)
            {
                mouseState = MouseState.Pressed;
                GoToState(true, "Pressed");
            }
        }

        /// <summary>
        /// (Override) Handles Key Up events for the <see cref="ButtonBase"/> instance.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Input.KeyEventArgs"/> for the event</param>
        protected override void OnKeyUp(KeyEventArgs e)
        {
            base.OnKeyUp(e);
            if (this.IsEnabled && e.Key == Key.Space)
            {
                if (mouseState != MouseState.Normal)
                {
                    mouseState = MouseState.MouseOver;
                    GoToState(true, "MouseOver");
                }
                else
                {
                    mouseState = MouseState.Normal;
                    GoToState(true, "Normal");
                }

                OnClick();
            }
        }
    }
}
